
#include "StdAfx.h"

#include <windows.h>

#include "CDelare.h"

#include "smpio.h"


const TCHAR* CDescriptor::m_pDescriptorS[]=
{
	_T("static"),
	_T("const"),
	_T("valtile"),
	_T("extern"),

	0
};
DWORD CDescriptor::Parse(const _TCHAR* pstr, DWORD idEnd)
{
	DWORD id=0;

	if(0==idEnd)
	{
		idEnd=_tcslen(pstr);
	}

	for(DWORD i=0; m_pDescriptorS[i]!=NULL; i++)
	{
		if(i>=idEnd)
		{
			break;
		}

		id+=EatWhite(pstr+id);
		if(0==memcmp(pstr+id, m_pDescriptorS[i], _tcslen(m_pDescriptorS[i])*sizeof(TCHAR) ) )
		{
			id+=_tcslen(m_pDescriptorS[i]);
			m_vDescriptorIDS.push_back(i);
			i=0;			// find next
		}
	}
	
	return id;
};

bool CDescriptor::GetDescriptor(_tstring strDescriptor)
{
	if(0==m_vDescriptorIDS.size())
	{
		return false;
	}
	
	for(DWORD i=0; i<m_vDescriptorIDS.size(); i++)
	{
		strDescriptor+=m_pDescriptorS[i];
	}

	return true;
}
	
bool CDescriptor::IsConst()
{
    if(m_vDescriptorIDS.end()==find(m_vDescriptorIDS.begin(), m_vDescriptorIDS.end(), 1))
    {
        return false;
    }

    return true;
}

bool CDescriptor::IsStatic()
{
    if(m_vDescriptorIDS.end()==find(m_vDescriptorIDS.begin(), m_vDescriptorIDS.end(), 0))
    {
        return false;
    }

    return true;
}

const BaseTypeInfo CType::m_pBaseTypeS[]=
{
	{_T("void"), btVoid, 0},
	{_T("bool"), btBool, 1},
	{_T("__wchar_t"), btWChar, 2},
	{_T("wchar_t"), btWChar, 2},
	{_T("double"), btFloat, 8},
	{_T("float"), btFloat, 4},

	{_T("char"), btChar, 1},
	{_T("short"), btInt, 2},
	{_T("int"), btInt, 4},
	{_T("__int8"), btChar, 1},
	{_T("__int16"), btInt, 2},
	{_T("__int32"), btInt, 4},
	{_T("__int64"), btInt, 8},
	{_T("long long"), btInt, 8},
	{_T("long"), btLong, 4},

	{_T("unsigned char"), btUInt, 1},
	{_T("unsigned short"), btUInt, 2},
	{_T("unsigned int"), btUInt, 4},
	{_T("unsigned __int8"), btUInt, 1},
	{_T("unsigned __int16"), btUInt, 2},
	{_T("unsigned __int32"), btUInt, 4},
	{_T("unsigned __int64"), btUInt, 8},
	{_T("unsigned long long"), btUInt, 8},
	{_T("unsigned long"), btULong, 4},

	{0}
};

DWORD CType::Parse(const _TCHAR* pstr, DWORD idEnd)
{
	DWORD id=0;

	// eat "signed"
	id+=EatWhite(pstr);
	if(0==memcmp(pstr+id, _T("signed"), _tcslen(_T("signed"))*sizeof(TCHAR) ) )
	{
		id+=_tcslen( _T("signed"));
		id+=EatWhite(pstr+id);
	}
	
	// find basic type if has
	for(DWORD i=0; m_pBaseTypeS[i].pszName!=NULL; i++)
	{
		if(0==memcmp(pstr+id, m_pBaseTypeS[i].pszName, _tcslen(m_pBaseTypeS[i].pszName)*sizeof(TCHAR)))
		{
			id+=_tcslen(m_pBaseTypeS[i].pszName);
			m_strType=m_pBaseTypeS[i].pszName;
			m_dwBasicType=i;
			return id;
		}
	}
	
	// type
	int iWhite=FindWhite(pstr+id, 0);
	if(-1==iWhite)
	{
		m_strType=pstr+id;
	}
	else
	{
		m_strType=_tstring(pstr+id, iWhite);
	}
	
	return id+iWhite;
};

bool CType::GetType(_tstring* pstrType)
{
	if(0==m_strType.size())
	{
		return false;
	}
	
	*pstrType=m_strType;
	return true;
};

bool CType::GetBasicTypeDiaInfo(BaseTypeInfo* pBscTpDiaInfo)
{
	if(INVALID_DWORD==m_dwBasicType)
	{
		return false;
	}
	
	*pBscTpDiaInfo=m_pBaseTypeS[m_dwBasicType];
	return true;
};


DWORD CPrefix::Parse(const _TCHAR* pstr, DWORD idEnd)
{
	DWORD id=EatWhite(pstr);

	if(_T('&')==pstr[id])
	{
		m_Fixer.enType=DCL_FIX_REF;
		return id+1;
	}

	if(_T('*')==pstr[id])
	{
		id++;
		id+=EatWhite(pstr+id);
		if(0==memcmp(pstr+id, _T("const"), _tcslen(_T("const"))*sizeof(TCHAR) ))
		{
			m_Fixer.enType=DCL_FIX_CNST_PTR;
			return id+_tcslen(_T("const"));
		}
		else
		{
			m_Fixer.enType=DCL_FIX_PTR;
			return id;
		}
	}
	
	return 0;
}

bool CPrefix::IsPrefix(const TCHAR* pstr)
{
	int id=EatWhite(pstr);
	switch(pstr[id])
	{
	case _T('&'):
	case _T('*'):
		return true;
	}
	
	return false;
}

DWORD CPostfix::Parse(const TCHAR* pstr, DWORD idEnd)
{
	DWORD id=EatWhite(pstr);

	if(0==idEnd)
	{
		idEnd=_tcslen(pstr);
	}

	if(_T('[')==pstr[id])
	{
		id++;
		const TCHAR* pEnd=find_if(pstr+id, pstr+idEnd, FnObFindPairEnd<const TCHAR>(_T('['), _T(']')));
		if(pEnd==pstr+idEnd)
		{
			return 0;
		}
		
		id+=EatWhite(pstr+id);
		_tstring strDim(pstr+id, pEnd-(pstr+id));
		DWORD dwDim;
		StringCnvt(strDim, &dwDim);
		m_Fixer.enType=DCL_FIX_ARRAY;
		m_Fixer.dwArrayDim=dwDim;
		
		return pEnd-pstr+1;		// +1 "]"
	}
	
	return 0;
}

bool CPostfix::IsPostfix(const TCHAR* pstr)
{
	int id=EatWhite(pstr);
	if(_T('[')==pstr[id])
	{
		return true;
	}
	
	return false;
}


bool CPriorityModifier::IsPriorityModifier(const TCHAR* pstr)
{
	int id=EatWhite(pstr);
	if(_T('(')!=pstr[id])
	{
		return false;
	}
	id++;

	const TCHAR* pEnd=find_if(pstr+id, pstr+_tcslen(pstr+id)+id, FnObFindPairEnd<const TCHAR>(_T('('), _T(')')));
	if(pEnd==(pstr+_tcslen(pstr+id)+id))
	{
		return false;
	}
	return true;
};

DWORD CPriorityModifier::FindEnd(const TCHAR* pstr, DWORD idEnd)
{
	DWORD id=EatWhite(pstr);
	if(_T('(')!=pstr[id])
	{
		return 0;
	}
	id++;

	if(idEnd==0)
	{
		idEnd=_tcslen(pstr);
	}

	const TCHAR* pEnd=find_if(pstr+id, pstr+idEnd, FnObFindPairEnd<TCHAR>(_T('('), _T(')')));
	if(pEnd>=(pstr+idEnd))
	{
		return 0;
	}
	
	return pEnd-pstr;
}


DWORD CDeclarator::Parse(const TCHAR* pstr, DWORD idEnd)
{
	static TCHAR chEnds[]={_T(' '),_T('\t'),_T('*'),_T('[')};

	DWORD id=EatWhite(pstr);
	if(0==idEnd)
	{
		idEnd=_tcslen(pstr);
	}

	DWORD idWhite=FindCharS(pstr+id, chEnds, ARRAYOF(chEnds), idEnd-id); // find white and key word
	if(INVALID_DWORD!=idWhite)
	{
		idWhite+=id;
	}
	else
	{
		idWhite=idEnd;
	}
	
	m_Declarator=_tstring(pstr+id, idWhite);	// -1 ")"
	return idWhite;
};


bool CDeclarator::GetDeclarator(_tstring* pDeclarator)
{
	if(0==m_Declarator.size())
	{
		return false;
	}

	*pDeclarator=m_Declarator;
	return true;
}

CDeclare::~CDeclare()
{
	for(vector<CFixer*>::iterator it=m_vpFixerS.begin(); it!=m_vpFixerS.end(); it++)
	{
		delete *it;
	}

}

bool CDeclare::Parse()
{
	const TCHAR* pDeclare=m_strDeclare.c_str();
	DWORD iLen=_tcslen(pDeclare);
	
	DWORD id=m_Discriptor.Parse(pDeclare);
	if(id==iLen)
	{
		return false;
	}
		
	int iEat=m_Type.Parse(pDeclare+id);
	if(0==iEat)
	{
		TRACE(_T("no type!\r\n"));
		return false;
	}
	id+=iEat;

	if(id==iLen)
	{
		return true;	// we can only special type
	}
	
	return PaseDeclarator(pDeclare+id, 0, &m_vpFixerS);
}

bool CDeclare::PaseDeclarator(const TCHAR* pDeclarator, DWORD idEnd, 	vector<CFixer*>* pvpFixerS)
{
	if(0==idEnd)
	{
		idEnd=_tcslen(pDeclarator);
	}

	DWORD id=0;
	DWORD iLen;

	while(id<idEnd)
	{
		if(CPrefix::IsPrefix(pDeclarator+id))
		{
			pvpFixerS->push_back(new CPrefix);
			id+=pvpFixerS->back()->Parse(pDeclarator+id);
			if(id==idEnd){return true;}
		}
		else if(CPostfix::IsPostfix(pDeclarator+id))
		{
			pvpFixerS->push_back(new CPostfix);
			id+=pvpFixerS->back()->Parse(pDeclarator+id);
			if(id==idEnd){return true;}
		}
		else if(CFunPtr::IsFunPtr(pDeclarator+id))
		{
			//1 ???
		}
		else if(CPriorityModifier::IsPriorityModifier(pDeclarator+id))
		{
			iLen=CPriorityModifier::FindEnd(pDeclarator+id);
			if(0==iLen)
			{
				return false;	// not find end
			}
			id++;

			vector<CFixer*> vpFixer;
			if(!PaseDeclarator(pDeclarator+id, iLen-1, &vpFixer))	//-1 -")"
			{
				return false;
			}
			pvpFixerS->insert(pvpFixerS->begin(), vpFixer.begin(), vpFixer.end());
			id+=iLen;
		}
		else
		{
			id+=EatWhite(pDeclarator+id);
			if(id>=idEnd)
			{
				break;
			}

			if(m_Declarator.IsValid())
			{
				return false;	// only can have one delcaraor
			}
			iLen=m_Declarator.Parse(pDeclarator+id, idEnd-id);
			if(0==iLen)
			{
				return false;	// not find end
			}
			id+=iLen;
		}
	}

	return true;

};

bool CDeclare::GetDclFixStr(_tstring* pstrFix)
{
	for(vector<CFixer*>::iterator it=m_vpFixerS.begin(); it!=m_vpFixerS.end(); it++)
	{
		(*it)->AppendDclFixStr(pstrFix);
	}

	return true;
}

VOID CDeclare::GetDclFixS(vector<CDclFix>* pvectDclFixS)
{
	for(vector<CFixer*>::iterator it=m_vpFixerS.begin(); it!=m_vpFixerS.end(); it++)
	{
		pvectDclFixS->push_back(*(*it)->GetDclFix());
	}
}


bool CDeclare::GetDeclare(_tstring* pstrDclr)
{
	_tstring strType, strDclr, strFix;
	if( GetType(&strType)
		&& GetDeclarator(&strDclr)
		&& GetDclFixStr(&strFix))
	{
		*pstrDclr+=strType;
		*pstrDclr+=strDclr;
		*pstrDclr+=strFix;

		return true;
	}

	return false;
}

